#pragma once
#include <iostream>
#include <string>
#include "myh/socket.hpp"
#include "myh/MyLog.hpp"
#include "myh/pthreadpool.hpp"
#include <memory>
#include <mutex>
#include <unistd.h>
#include <csignal>
#include <fstream>
#include "serialization.hpp"
#include <ctime>
class tcpclient
{
    typedef std::shared_ptr<tcpclient> TcpPtr;
    typedef std::shared_ptr<Socket> SocketPtr;
    static const size_t SIZE = 1024;

    typedef void (*task)(int);
    static void handle_clock(int sig)
    {
        if (_this->_is_clock)
            _this->_is_run = false;
    }

    static void Read(int fd)
    {
        char buffer[SIZE];
        while (true)
        {
            int n = read(fd, buffer, SIZE);
            if (n == 0)
            {
                break;
            }
            else if (n < 0)
            {
                break;
            }
            else
            {
                buffer[n] = 0;
                std::string s = Unpack(buffer);
                auto &rpg = ResultPackage::Getinitance();
                rpg.Deserialization(s);
                int result = rpg.GetResult();
                int code = rpg.GetCode();
                // Correct,
                // DivisionError,
                // FormatError,
                // LabelError
                std::string codestr = _this->CodeError(code);
                _this->Print(result,codestr);
            }
        }
    }

    void Print(int result,const std::string& codestr)
    {
        printf("_____________________________________________\n");
        printf("%s         结果为:%d\n",codestr.c_str(),result);
        printf("_____________________________________________\n");
    }

    std::string CodeError(int code)
    {
        switch (code)
        {
        case Correct:
            return "结果正确";
        case DivisionError:
            return "除零错误";
        case FormatError:
            return "格式错误";
        case LabelError:
            return "符号错误";
        default:
            return "未知错误";
        }
    }

    struct Readfun
    {
        Readfun(task read, int fd)
            : _read(std::move(read)), _fd(fd)
        {
        }
        task _read;
        int _fd;
        void operator()()
        {
            _read(_fd);
        }
    };

    void ReqSer()
    {
        PthPool<Readfun>::Getinitance(1);
        PthPool<Readfun>::Getinitance()->start();
        std::string s;
        int sockfd = _this->_csocket->GetSockfd();
        PthPool<Readfun>::Getinitance()->push(Readfun(Read, sockfd));
        auto &cpck = ContentPackage::Getinitance();
        int x, y;
        char op;
        srand(time(nullptr));
        char ops[4] = {'+', '-', '*', '/'};
        while (_is_run)
        {
            x = rand() % 1000;
            y = rand() % 1000;
            op = ops[rand() % 4];
            cpck.AddDate(x, y, op);
            cpck.Serialization(s);
            s = Package(s);
            std::cout << "发送:\n" << s << std::endl;
            int n = write(sockfd, s.c_str(), s.size());
            if (n < 0)
            {
                lg.defaultprint("write", errno);
                break;
            }
            sleep(1);
            s.clear();
        }
    }

public:
    void run()
    {
        signal(SIGALRM, handle_clock); // 处理重新连接问题
        sockaddr_in serveaddr;
        std::string s;
        while (_is_run)
        {
            int ret = _this->_csocket->Connect();
            if (ret < 0)
            {
                // 准备重连
                if (!_is_clock)
                {
                    alarm(5); // 设置重连时间
                    _is_clock = true;
                }
            }
            else
            {
                _is_clock = false;
                // 发送请求
                ReqSer();
                _this->_csocket->Close();
                break;
            }
        }
    }

    static TcpPtr Getinitance(uint16_t port = 0, const std::string &ip = "", int domain = AF_INET)
    {
        static std::once_flag once;
        std::call_once(once, [port, ip, domain]()
                       { _this = TcpPtr(new tcpclient(port, ip, domain)); });
        return _this;
    }

private:
    tcpclient(const tcpclient &u) = delete;
    tcpclient &operator=(const tcpclient &u) = delete;
    tcpclient(uint16_t port, const std::string &ip, int domain = AF_INET)
        : _csocket(SocketPtr(new Socket(port, ip, domain, SOCK_STREAM)))
    {
    }

private:
    bool _is_run = true;
    bool _is_clock = false;

    SocketPtr _csocket;
    static TcpPtr _this;
};

tcpclient::TcpPtr tcpclient::_this = nullptr;